<?php

namespace app\admin\controller\recommend;

use app\admin\controller\shop\Base;
use app\shop\library\ShopHelper;
use app\shop\library\ShopLogHelper;
use think\db\exception\DataNotFoundException;
use think\db\exception\DbException;
use think\db\exception\ModelNotFoundException;
use think\helper\Arr;
use Throwable;

class Setting extends Base
{
    protected array $noNeedPermission = ['getSensitiveFieldValue'];

    /**
     * 配置分组键名
     * @var string
     */
    protected string $configGroupKey = '';

    public function initialize(): void
    {
        parent::initialize();

        $this->model = new \app\admin\model\recommend\Setting();
    }

    public function index(): void
    {
        $this->success('', $this->getList());
    }

    /**
     * 获取配置列表
     * @return array
     * @throws DataNotFoundException
     * @throws DbException
     * @throws ModelNotFoundException
     */
    public function getList(): array
    {
        $configGroup = [];
        $groupWhere  = [];
        $group       = $this->model->where(['group' => $this->configGroupKey])->findOrEmpty();
        if (!$group->isEmpty()) {
            $configGroup  = $group['value'];
            $groups       = array_unique(array_column($configGroup, 'key'));
            $groupWhere[] = ['group', 'in', $groups];
        }
        $config         = $this->model->where($groupWhere)->order(['weigh' => 'asc'])->select()->toArray();
        $list           = [];
        $newConfigGroup = [];
        foreach ($configGroup as $item) {
            $list[$item['key']]['name']   = $item['key'];
            $list[$item['key']]['title']  = __($item['value']);
            $newConfigGroup[$item['key']] = $list[$item['key']]['title'];
        }
        foreach ($config as $item) {
            if ($item['type'] === 'password' && is_string($item['value'])) {
                $item['value'] = str_replace($item['value'], '**********', $item['value']);
            }
            if (array_key_exists($item['group'], $newConfigGroup)) {
                $item['title']                  = __($item['title']);
                $list[$item['group']]['list'][] = $item;
            }
        }

        return [
            'list'        => $list,
            'remark'      => get_route_remark(),
            'configGroup' => $newConfigGroup ?? [],
        ];
    }

    /**
     * 保存配置项
     * @throws Throwable
     */
    public function save(): void
    {
        $group = $this->model->where(['group' => $this->configGroupKey])->value('value');
        if (!$group) {
            $this->error('配置分组异常');
        }
        $groupKeys = array_column(ShopHelper::json_to_array($group), 'key');
        $all       = $this->model->whereIn('group', $groupKeys)->select();
        foreach ($all as $item) {
            if ($item['type'] == 'editor') {
                $this->request->filter('clean_xss');
                break;
            }
        }
        if ($this->request->isPost()) {
            $data = $this->request->post();
            if (!$data) {
                $this->error(__('Parameter %s can not be empty', ['']));
            }
            $data = $this->excludeFields($data);

            foreach ($data as $key => $value) {
                // 过滤值为**********的密码类型
                if ($value == '**********') {
                    unset($data[$key]);
                }
            }

            $data = $this->beforeSave($data);

            $result = false;
            $this->model->startTrans();
            try {
                $updateData = [];
                foreach ($all as $item) {
                    // 只更新有变化的数据
                    if (array_key_exists($item['name'], $data) && $item->value !== $data[$item['name']]) {
                        $updateData[] = [
                            'id'    => $item['id'],
                            'value' => $data[$item['name']],
                            'type'  => $item['type'],
                        ];
                    }
                }
                $result = $this->model->saveAll($updateData);
            } catch (Throwable $e) {
                $this->model->rollback();
                ShopLogHelper::error('配置项更新失败', ['update_data' => $updateData], $e);
                $this->error($e->getMessage());
            }

            if ($result === false) {
                $this->model->rollback();
                $this->error('配置项更新失败');
            } else {
                $this->afterSave($data);

                $this->model->commit();
                $this->success(__('当前页配置项更新成功'));
            }
        }
    }

    /**
     * 配置项保存前置方法
     * @param array $data 配置项数据
     * @return array 返回配置项数据
     */
    protected function beforeSave(array $data): array
    {
        return $data;
    }

    /**
     * 配置项保存后置方法
     * @param array $data 配置项数据
     * @return void
     */
    protected function afterSave(array $data): void { }

    /**
     * 添加变量
     * @throws Throwable
     */
    public function add(): void
    {
        if ($this->request->isPost()) {
            $data = $this->request->post();
            if (!$data) {
                $this->error(__('Parameter %s can not be empty', ['']));
            }

            $data   = $this->excludeFields($data);
            $result = false;

            $this->model->startTrans();

            try {
                // 模型验证
                $validate = new \app\admin\validate\shop\Setting();
                if ($this->modelSceneValidate) $validate->scene('add');
                $validate->check($data);

                $this->beforeWrite($data);

                $result = $this->model->save($data);

                $this->model->commit();
            } catch (Throwable $e) {
                $this->model->rollback();
                $this->error($e->getMessage());
            }
            if ($result !== false) {
                $this->success(__('Added successfully'), $this->getList());
            } else {
                $this->error(__('No rows were added'));
            }
        }

        $this->error(__('Parameter error'));
    }

    /**
     * 编辑变量
     * @return void
     */
    public function edit(): void
    {
        // 编辑展示
        if ($this->request->isGet()) {
            $id = $this->request->get('id');
            if (!$id) {
                $this->error(__('Parameter error'));
            }
            $result = $this->model->append(['input_extend'])->findOrEmpty($id);

            if ($result->isEmpty()) {
                $this->error(__('Record not found'));
            }
            $result = $result->toArray();

            $result['rule']        = $result['rule'] ? explode(',', $result['rule']) : '';
            $result['content']     = $this->formatContentOrExtendData($result['content']);
            $result['extend']      = $this->formatContentOrExtendData($result['extend']);
            $result['inputExtend'] = $this->formatContentOrExtendData($result['input_extend']);

            $this->success('', $result);
        }

        // 编辑操作
        if ($this->request->isPost()) {
            $data = $this->request->post();
            if (!$data) {
                $this->error(__('Parameter %s can not be empty', ['']));
            }
            $config = $this->model->where(['name' => $data['name']])->findOrEmpty();
            if ($config->isEmpty()) {
                $this->error(__('Record not found'));
            }

            unset($data['name']);
            $result = false;
            $this->model->startTrans();
            try {
                $this->beforeWrite($data);
                $result = $config->save($data);
            } catch (Throwable $e) {
                $this->model->rollback();
                $this->error($e->getMessage());
            }

            if ($result !== false) {
                $this->model->commit();
                $this->success(__('Update successful'));
            } else {
                $this->error(__('No rows updated'));
            }
        }
    }

    /**
     * 格式化content或者extend数据
     * @param $extendData
     * @return array|string
     */
    private function formatContentOrExtendData($extendData): array|string
    {
        $result = [];

        if (!$extendData) return $result;

        foreach ($extendData as $key => $value) {
            if (is_bool($value)) {
                $value = $value ? 'true' : 'false';
            }
            $result[] = implode('=', [$key, $value]);
        }

        return implode("\n", $result);
    }

    /**
     * 编辑配置分组
     * @return void
     * @throws DataNotFoundException
     * @throws DbException
     * @throws ModelNotFoundException
     */
    public function editGroup(): void
    {
        $data = $this->request->post();
        if (!$data || !Arr::has($data, 'value')) {
            $this->error(__('Parameter %s can not be empty', ['']));
        }
        $groupValue = $data['value'];
        $keys       = array_column($groupValue, 'key');
        if (count($keys) !== count(array_unique($keys))) {
            $this->error("分组变量名不能重复");
        }
        $configModel = $this->model->where(['group' => $this->configGroupKey])->findOrEmpty();
        if ($configModel->isEmpty()) {
            //添加配置分组
            $result = $this->model->save([
                'name'        => $this->configGroupKey,
                'group'       => $this->configGroupKey,
                'type'        => 'array',
                'value'       => $groupValue,
                'rule'        => 'required',
                'extend'      => '',
                'inputExtend' => ''
            ]);
        } else {
            $configValues = $configModel->toArray();
            $configKeys   = array_column($configValues['value'], 'key');
            $configGroups = $this->model->where('id', '<>', $configValues['id'])->whereNotIn('group', $configKeys)->distinct()->column('group');
            foreach ($groupValue as $config) {
                if (in_array($config['key'], $configGroups)) {
                    $this->error("分组变量名【{$config['key']}】与其他配置分组名冲突");
                }
            }

            $result = $configModel->save($data);
        }

        if ($result !== false) {
            $this->success(__('配置分组更新成功'), $this->getList());
        } else {
            $this->error(__('配置分组更新失败'));
        }
    }

    /**
     * 数据入库前转化
     * @param array $data
     * @return void
     */
    private function beforeWrite(array &$data): void
    {
        if (!in_array($data['type'], $this->model->getNeedContent())) {
            $data['content'] = null;
        } else {
            $content         = Arr::has($data, 'content') ? $data['content'] : '';
            $data['content'] = shopHelper::array_to_json(str_attr_to_array($content));
        }
        if (is_array($data['rule'])) {
            $data['rule'] = implode(',', $data['rule']);
        }
        if ($data['extend'] || $data['inputExtend']) {
            $extend = $data['extend'];
            if (is_string($extend)) {
                $extend = str_attr_to_array($extend);
            }
            if (!empty($data['inputExtend'])) {
                $inputExtend             = str_attr_to_array($data['inputExtend']);
                $extend['baInputExtend'] = $inputExtend;
            }
            if ($extend) {
                $data['extend'] = shopHelper::array_to_json($extend);
            }
        }

    }

    /**
     * 根据变量名获取值(敏感数据)
     * @throws Throwable
     */
    public function getSensitiveFieldValue(): void
    {
        $pathInfo      = str_replace('.', '/', request()->pathinfo());
        $saveAuthority = str_replace('getSensitiveFieldValue', 'save', $pathInfo);
        $ruleList      = $this->auth->getRuleList($this->auth->id);

        if (in_array(strtolower($pathInfo), $ruleList) || in_array(strtolower($saveAuthority), $ruleList)) {
            $name = $this->request->post('name', '');
            if (!$name) {
                $data = '';
            } else {
                $config = $this->model->where('name', '=', $name)->field('value')->findOrEmpty();
                $data   = $config->isEmpty() ? '' : $config['value'];
            }

            $this->success('', $data);
        } else {
            $this->error('没有权限操作！');
        }
    }
}